package com.kayb.patterns.behavioral;

import java.util.ArrayList;
import java.util.List;

/**
 * 访问者模式，一种分离对象数据结构与行为的方法，可以为某个被访问者动态增加新操作而无须做其他修改。
 * 场景：数据结构中的对象很少变化，但
 * @author huangkaibin
 * @date 2018-08-29
 **/
public class Visitor {

    interface IVisitor {
        void visit(Customer object);
        void visit(Order object);
        void visit(Item object);
    }

    interface IObject {
        void accept(IVisitor visitor);
    }

    static class Customer implements IObject {
        private String name;
        private List<Order> orders = new ArrayList<>();

        Customer(String name) {
            this.name = name;
        }

        String getName() {
            return name;
        }

        void addOrder(Order order) {
            orders.add(order);
        }

        public void accept(IVisitor visitor) {
            visitor.visit(this);
            for (Order order : orders) {
                order.accept(visitor);
            }
        }
    }

    static class Order implements IObject {
        private String name;
        private List<Item> items = new ArrayList<>();

        Order(String name) {
            this.name = name;
        }

        Order(String name, String itemName) {
            this.name = name;
            this.addItem(new Item(itemName));
        }

        String getName() {
            return name;
        }

        void addItem(Item item) {
            items.add(item);
        }

        public void accept(IVisitor visitor) {
            visitor.visit(this);

            for (Item item : items) {
                item.accept(visitor);
            }
        }
    }

    static class Item implements IObject {
        private String name;

        Item(String name) {
            this.name = name;
        }

        String getName() {
            return name;
        }

        public void accept(IVisitor visitor) {
            visitor.visit(this);
        }
    }

    static class Reporter implements IVisitor {
        private int customersNo;
        private int ordersNo;
        private int itemsNo;

        public void visit(Customer customer) {
            System.out.println(customer.getName());
            customersNo++;
        }

        public void visit(Order order) {
            System.out.println(order.getName());
            ordersNo++;
        }

        public void visit(Item item) {
            System.out.println(item.getName());
            itemsNo++;
        }

        public void print() {
            System.out.println("Number of customers: " + customersNo);
            System.out.println("Number of orders:    " + ordersNo);
            System.out.println("Number of items:     " + itemsNo);
        }
    }

    public static void main(String[] args) {
        Customer customer1 = new Customer("customer1");
        customer1.addOrder(new Order("order1", "item1"));
        customer1.addOrder(new Order("order2", "item1"));
        customer1.addOrder(new Order("order3", "item1"));

        Reporter visitor = new Reporter();
        customer1.accept(visitor);
        visitor.print();
    }

}
